/**
*
 * Preemptive Least Laxity First
 * 03/02
* see <a href="{@docRoot}/Documentation/scheduler.html"> for more information</a>
*  Copyright (c) 2009 Ecole Centrale de Nantes IRCCyN
* @author: amd
* @version 3.2
*/
package storm.Schedulers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;

import storm.EvtContext;
import storm.Processors.LEATProcessor;
import storm.Processors.Processor;
import storm.Tasks.Task;



/**
 * 
 * @author AMD
 *
 */
public class RR_TEST_Scheduler extends Scheduler {
	/**
	 * 
	 * @author AMD
	 *
	 */
	class LReady extends ArrayList implements Comparator {
		/**
		 * 
		 */
		public int compare(Object arg0, Object arg1) {
			Task T0 = (Task) arg0;
			Task T1 = (Task) arg1;
			int d0 = T0.getOwnFieldIntValue("last_slot");
			int d1 = T1.getOwnFieldIntValue("last_slot");
			if (d1 > d0) return -1;
			else if (d1 == d0) return 0;
			     else return 1;
		}
		
	}
	/**
	 * 
	 */
	private LReady list_ready;
	private Boolean todo = false;
	/**
	 * 
	 */
	public void init() {
		super.init();
		list_ready = new LReady();
	}
	/**
	 * 
	 */
	public void onActivate(EvtContext c) {
		Task T = (Task)c.getCible();
		System.out.println(T.getId() + " " + T.isready + "  " + T.iswaiting);
		T.setOwnFieldIntValue("count",this.getOwnFieldIntValue("quantum"));
		T.setOwnFieldIntValue("last_slot",this.Kernel.getTime());
		list_ready.add(T);
		/**
		 * reordonnancement necessaire uniquement s'il y a des processeurs libres
		 */
		ArrayList CPUS =this.Kernel.getTasksListeManager().getProcessors();
		Iterator iCPU = CPUS.iterator();
		while (iCPU.hasNext() && !todo) {
			Processor p = (Processor) iCPU.next();
			if (!p.isRunning()) {
				todo = true;
			}
		}
	}

	public void onUnBlock(EvtContext c){
		Task T = (Task)c.getSource();	
		if (T.isBegin()) {
			T.setOwnFieldIntValue("count",this.getOwnFieldIntValue("quantum"));
			int d = T.getOwnFieldIntValue("count");
		}
		list_ready.add(T);
		/**
		 * reordonnancement necessaire uniquement s'il y a des processeurs libres
		 */
		ArrayList CPUS =this.Kernel.getTasksListeManager().getProcessors();
		Iterator iCPU = CPUS.iterator();
		while (iCPU.hasNext() && !todo) {
			Processor p = (Processor) iCPU.next();
			if (!p.isRunning()) {
				todo = true;
			}
		}
	}
	/**
	 * 
	 */
	public void onBlock(EvtContext c){
		list_ready.remove(c.getCible());
		Task T = (Task) c.getCible();

		/**
		 * reordonnancement necessaire uniquement si cette tache quitte l'etat Running
		 * MaJ de son dernier slot d'execution
		 */
		if (T.predStateIsRunning()) {
			T.setOwnFieldIntValue("last_slot",this.Kernel.getTime());
			todo = true;
		}
	}
	/**
	 * 
	 */
	public void onTerminated(EvtContext c){
		list_ready.remove(c.getCible());
		// reordonnancement necessaire
		todo = true;
	}
	/**
	 * 
	 */
	public void onTick(){
		ArrayList CPUS =this.Kernel.getTasksListeManager().getProcessors();;
		Iterator ICPU = CPUS.iterator();
		/**
		 *TEst
		 *
		 */
		ArrayList Tasks =this.Kernel.getTasksListeManager().getALLTask();
		Iterator K = Tasks.iterator();
	//	System.out.println("/********************************/");
		while (K.hasNext()){
			Task T = (Task) K.next();
			System.out.println(T.isEverRunning()+ "    " + T.getRET());
		//	System.out.println(T.getDeadlineDate()+ " --  " + T.getDeadlineCountDate()  + " -- " +T.getDeadline());
		}
		/**
		 * MaJ de count pour les seules taches dans l'etat Running
		 */
		while(ICPU.hasNext()){
			Processor CPU = (Processor) ICPU.next();
			if (CPU.isRunning()) {
					Task T = CPU.getrunning();
					int c = T.getOwnFieldIntValue("count");
					c = c-1;
					T.setOwnFieldIntValue("count",c);
					if (c==0) {
                      	T.setOwnFieldIntValue("last_slot",this.Kernel.getTime());
						/**
						 * reordonnancement necessaire
						 */
						todo = true;
					}
			}
		}
	}
	
	public void sched(){
		if (todo) {
			select();
			todo = false;
		}
	}
	
	public void select() {
		Collections.sort(list_ready,list_ready);
		for (int i=0; i<list_ready.size(); i++){
			Task T = (Task) list_ready.get(i);
			int s = T.getOwnFieldIntValue("last_slot");
			int c = T.getOwnFieldIntValue("count");
		}
		
		ArrayList CPUS =this.Kernel.getTasksListeManager().getProcessors();
		int m = CPUS.size();	// m = nb processeurs 
		/** 
		 * Les m (au +) taches les + prios sont en tete de la liste
		 * les suivantes doivent etre si necessaire preemptees
		 */
		for (int i=m; i<list_ready.size(); i++){
			Task T = (Task) list_ready.get(i);
			if (T.isIsrunning()) T.preempt();
		}
		/**
		 * construction de la liste des processeurs actuellement libres
		 */
		ArrayList freeProcList = new ArrayList();
		Iterator iCPU = CPUS.iterator();
		while (iCPU.hasNext()) {
			Processor p = (Processor) iCPU.next();
			if (!p.isRunning()) {
				freeProcList.add(p);
			}
		}
		
		/**
		 * on affecte si possible a chacun des processeurs libres une tache parmi les + prios
		 * sans changer l'affectation des taches deja Running
		 */
		int j = 0;
		for (int i=0; (j<freeProcList.size()) && (i<list_ready.size()); i++){
			Task T = (Task) list_ready.get(i);
			if (!T.isIsrunning()) {
				Processor P = (Processor) freeProcList.get(j);
				T.runningOn(P);
				if (P instanceof LEATProcessor){
					//Change frequency in time 
			/*		LEATProcessor LP = (LEATProcessor) P;
					if (LP.isRunning() ) {
						Task Ta = LP.getrunning();
						LP.setFreq(T.getOwnFieldIntValue("freq"));
					}
*/					
				}
				
				T.setOwnFieldIntValue("count",this.getOwnFieldIntValue("quantum"));
				j++;
			}
		}
		
		
	}

}
